home *** CD-ROM | disk | FTP | other *** search
- #pragma mark Includes<I
- //• ------------------------------ Includes
-
- #include <stdlib.h>
- #include <stdio.h>
-
- #pragma mark Prototypes<I
- //• ------------------------------ Prototypes
-
- void SetupMenus (void);
- void InitFireballs (void);
- void SetupEverything (void);
- short MunafoRandom (short n);
- void DrawANumber (long n);
- void UpdateScore (void);
- void DrawTheScore (void);
- void DrawBottomLine (void);
- void AllocateFireballs (Point location);
- void AdvanceFireballs (void);
- void AllocateMissiles (Point position, short city, short kind);
- Boolean BlackPixel (Point aPoint);
- void AdvanMS (void);
- void CenterSomeText (Str255 TheText, short posV);
- void ClearTheScreen (void);
- void DrawACity (short city);
- void DrawOurStuff (void);
- short NumStrMinMax (Str255 theString, short minimum, short MAXIMUM);
- void DoGameOptions (void);
- void DoCommand (long whichMenu);
- void CheckEvents (void);
- void GameOverScreen (void);
- void InitializeRound (void);
- void EndRoundBonus (void);
- void PlayMacMissile (void);
- void main (void);
- void SetPString (Str255 thePString, char *theCString);
-
- #pragma mark Constants<I
- //• ------------------------------ Private Constants
-
- #define FP_SHIFT 4 //• Number of positions to shift for Fixed-Point math
-
- #define rsrcMainMBAR 128 //• resource ID of our MBAR definition
-
- #define appleMenu 128 //• menu ID for desk accessory menu.
- #define iAbout 1
-
- #define fileMenu 129 //• menu ID for File menu.
- #define iQuit 1
-
- #define gameMenu 131 //• menu ID for Game menu.
- #define iPause 1
- #define iResume 2
- //-------------
- #define iOptions 4
- #define iNewGame 5
-
- #define aboutAlert 128 //• ID of "about" alert box.
- #define optionsDialog 129 //• ID of options box.
-
- #define fbIdle 0
- #define fbGrow 1
- #define fbShrink 2
- #define maxFB 60 //• Maximum number of fireballs allowed.
- #define fbRad 15 //• Radius of fireballs.
- #define fbRadRate 2 //• Rate of expansion/contraction of fireballs.
- #define msIdle 0
- #define msActive 1
- #define msNormal 1
- #define msMIRV 2
- #define msSmart 3
- #define maxMS 20 //• Maximum number of missiles allowed.
- #define mWidth 3 //• Width of missile tracks.
- #define cityHeight 40 //• Distance from bottom up to cities.
- #define cityWidth 50 //• Width of cities.
- #define buildHeight 30 //• Maximum height of buildings.
- #define buildWidth 4 //• Width of buildings.
- #define numCities 6 //• Number of cities.
-
- #pragma mark Definitions<I
- //• ------------------------------ Private Definitions
-
- typedef struct //• Data type to describe a fireball.
- {
- Rect bounds; //• Rectanggle to copy bits into.
- short size; //• Current radius of fireball.
- short mode; //• Idle, Growing, or shrinking.
- } fireball;
-
- typedef struct //• Data type to describe a missile.
- {
- Point start; //• One endpoint of the missile's path.
- Point pos; //• Position within path - 0 to 1.
- short dh, dv; //• Vertical and horizontal speed in pixels.
- short city; //• Number of the target city.
- short kind; //• MIRV or normal.
- short mode; //• Idle or Active.
- } missile;
-
- #pragma mark Globals<I
- //• ------------------------------ Private Variables
-
- Rect screenRect;
- Boolean doneFlag;
- EventRecord myEvent;
- short code, refNum;
- WindowPtr myWindow, whichWindow;
-
- BitMap fbBitMap; //• BitMap for fireball pictures.
- short fbBits[3601]; //• Actual bits for fireball pictures.
-
- Boolean roundOver = FALSE; //• Current round is over.
- CursHandle crosshair, crosshair2; //• Handle to the cursor.
- PatHandle cityPattern; //• Handle to pattern in which to draw cities.
- short fieldWidth; //• Width of the playing field.
- short fieldHeight; //• Height of the playing field.
- short i; //• Loop variable.
- fireball fbs[maxFB + 1]; //• Each entry describes one fireball.
- missile missiles[maxMS]; //• Each entry describes one missile.
- short nMissiles; //• Number of currently active missiles.
- long lastTick; //• System clock at time of previous update.
- Boolean gameOver; //• Set true when all cities are destroyed.
- Boolean pauseFlag; //• True when game is being paused.
- Boolean playing; //• True except buring bonus points and GAME OVER screens.
- Boolean esFlag; //• True if "GAME OVER" is to be drawn after exiting main loop.
- short endDelay; //• Used to wait a while after end of round.
- short citiesLeft; //• Number of cities still alive.
- short bonusCities; //• Number of bonus cities they have left.
- Boolean cities[numCities]; //• State of each city : false = destroyed.
- Boolean cities2[numCities]; //• State of the city before the round began.
- short nukeHeight; //• Vertical position of fireball required to destroy city.
- short endv; //• Y-coordinate of the end of a missile's path.
- short MIRV_Rate;
- short MIRV_Height; //• Height at which MIRVs MIRV.
- short MIRV_Nasty; //• Percent chance of sub-missile on MIRV for each city.
- short msSpeed; //• Vertical speed of missiles, in 1/16ths of a pixel..
- short msRate; //• Percent rate of missile production.
- short roundNumber; //• Number of the current round.
- long Score; //• The player's current score.
- long disScore; //• Score currently displayed on the screen.
- long highScore; //• The current highest score.
- short roundH;
- short scoreH; //• Horiz. position of text 'Score:.
- short scoreNumH; //• Horiz. position of score.
- short statsH; //• Horiz. position of text 'Enemy left:.
- short statsNumH;
- Rect statsRect;
- short eLeft; //• How many enemy missiles are left this round.
- short yLeft; //• How many missiles you (the player) have left.
- short eDestroyed; //• Number of enemy missiles destroyed.
- short eDesH; //• Horiz. position of text 'Enemy Destroyed:.
- short eDesNumH; //• Horiz. position of # of enemy missiles destroyed.
- short gameSpeed; //• Number of ticks between each Advance_Fireballs call.
- short startRound; //• Round to start off with.
- Boolean mFlag1; //• Do missiles aim for dead cities?.
- short mFlag2; //• Extent to which enemy missiles blow up.
- Boolean mExists[4]; //• Does this type of missile occur?.
- short mpBase[4]; //• Value of missile at first round...
- short mpExtra[4]; //• ...plus this much each additional round...
- short MPoints[4]; //• ...is this much in all.
-
- //• ------------------------------ SetupMenus
-
- void SetupMenus ()
- {
- Handle theMenuBar;
- MenuHandle tempMenu;
-
- //• Load the menu bar
- theMenuBar = GetNewMBar (rsrcMainMBAR);
-
- //• Install the menu bar
- SetMenuBar (theMenuBar);
- DrawMenuBar ();
-
- //• Add Apple Menu items
- AddResMenu (GetMHandle (appleMenu), 'DRVR');
- DisposeHandle (theMenuBar);
- }
-
- //• Init routine for fireball BitMaps..
- //• This routine is called by the main Init routine, below. It creates a
- //• bunch of bit images of circles off-screen, which can later be drawn on
- //• the screen much faster than FrameOval.
-
- //• ------------------------------ InitFireballs
-
- void InitFireballs ()
- {
- short i;
- Rect aRect; //• Rectangle for drawing FrameOvals.
- BitMap saveBits; //• To save the current GrafPort while drawing off-screen.
- Rect saveRect;
-
- saveBits = qd.thePort->portBits;
- saveRect = qd.thePort->portRect;
- fbBitMap.rowBytes = 8;
- SetRect (&fbBitMap.bounds, 0, 0, 60, 60);
- qd.thePort->portRect = fbBitMap.bounds;
-
- PenSize (fbRadRate, fbRadRate);
- PenPat (&qd.black);
- PenMode (patCopy);
-
- //• Start with an empty rectangle in the center.
- SetRect (&aRect, 30, 30, 30, 30);
-
- for (i = 0; i < 14; i++)
- {
- //• Pick starting address for this picture.
- fbBitMap.baseAddr = (Ptr) &fbBits[240 * i + 1];
-
- //• Make rect a bit larger.
- InsetRect (&aRect, -2, -2);
- SetPortBits (&fbBitMap);
- EraseRect (&qd.thePort->portBits.bounds); //• Erase to all white.
- FrameOval (&aRect); //• Draw the circle.
- }
-
- SetPortBits (&saveBits); //• Return to normal screen drawing.
- qd.thePort->portRect = saveRect;
- }
-
- //• ------------------------------ SetupEverything
-
- void SetupEverything ()
- {
- Rect wRect; //• Window Rectangle.
- short i;
-
- MaxApplZone ();
-
- //• Macintosh System initialization.
- InitGraf (&qd.thePort); //• Quickdraw.
- InitFonts (); //• Font Manager.
- InitWindows (); //• Window Manager.
- InitMenus (); //• Menu Manager.
- TEInit (); //• TextEdit.
- InitDialogs (0L); //• Dialog manager.
- InitCursor (); //• Cursor handler.
-
- SetupMenus (); //• My routine to insert the menus.
- crosshair = GetCursor (256); //• Load the Crosshairs cursor that I use in the game.
- HLockHi ((Handle) crosshair);
- SetCursor (*crosshair);
- cityPattern = GetPattern (256);
-
- doneFlag = false; //• This flag is set to False when user selects 'Quit'.
- highScore = 0;
-
- gameSpeed = 8; //• Set up all the user-settable options.
- startRound = 0;
- mFlag1 = true;
- mFlag2 = 1;
-
- for (i = 0; i < 3; i++)
- {
- mExists[i] = true;
- mpBase[i] = 10 * i;
- mpExtra[i] = 10 * i;
- }
-
- //• Might as well play the game in a window...
- myWindow = GetNewWindow (128, nil, (WindowPtr) -1L);
- SetPort (myWindow);
- ShowWindow (myWindow);
-
- //• These variables are used by the game.
- fieldWidth = myWindow->portRect.right;
- fieldHeight = myWindow->portRect.bottom;
-
- TextFont (0);
- TextFace (0);
-
- InitFireballs (); //• Set up the fireball BitMaps.
-
- FlushEvents (everyEvent, 0);
- }
-
- //• ------------------------------ ManufoRandom
-
- short
- MunafoRandom (short n)
- {
- short number;
-
- number = abs (Random ()) % n;
- return (number);
- }
-
- //• ------------------------------ DrawANumber
-
- void DrawANumber (long n)
- {
- Str255 s;
-
- NumToString (n, s);
- DrawString (s);
- }
-
- //• ------------------------------ UpdateScore
-
- void UpdateScore ()
- {
- TextMode (srcBic);
- MoveTo (scoreNumH, fieldHeight - 5);
- TextSize (24);
- DrawANumber (disScore);
-
- TextMode (srcOr);
- MoveTo (scoreNumH, fieldHeight - 5);
- DrawANumber (Score);
- disScore = Score;
-
- EraseRect (&statsRect);
- TextMode (srcOr);
- MoveTo (statsNumH, fieldHeight - 20);
- TextSize (12);
- DrawANumber (eLeft);
- MoveTo (statsNumH, fieldHeight - 5);
- DrawANumber (yLeft);
- TextMode (srcCopy);
- MoveTo (eDesNumH, fieldHeight - 20);
- DrawANumber (eDestroyed);
- }
-
- //• ------------------------------ DrawTheScore
-
- void DrawTheScore ()
- {
- TextMode (srcCopy);
- MoveTo (scoreH, fieldHeight - 14);
- TextSize (12);
- DrawString ("\pScore: ");
- MoveTo (scoreNumH, fieldHeight - 5);
- TextSize (24);
- DrawANumber (Score);
- disScore = Score;
-
- TextSize (12);
- MoveTo (statsH, fieldHeight - 20);
- DrawString ("\pEnemy left: ");
- DrawANumber (eLeft);
-
- MoveTo (statsH, fieldHeight - 5);
- DrawString ("\pYours left: ");
-
- MoveTo (statsNumH, fieldHeight - 5);
- DrawANumber (yLeft);
-
- MoveTo (eDesH, fieldHeight - 20);
- DrawString ("\pDestroyed: ");
-
- MoveTo (eDesNumH, fieldHeight - 20);
- DrawANumber (eDestroyed);
- }
-
- //• ------------------------------ DrawBottomLine
-
- void DrawBottomLine ()
- {
- TextSize (12);
- roundH = 10 + StringWidth ("\pRound: ");
- scoreH = roundH + 2 * StringWidth ("\p00 ");
- scoreNumH = scoreH + StringWidth ("\pScore: ");
- eDesH = fieldWidth - StringWidth ("\pDestroyed: 0000 ");
- eDesNumH = fieldWidth - StringWidth ("\p0000 ");
- statsH = eDesH - StringWidth ("\pEnemy left: 000 ");
- statsNumH = eDesH - StringWidth ("\p000 ");
-
- SetRect (&statsRect, statsNumH, fieldHeight - 30, eDesH-2, fieldHeight);
-
- TextMode (srcCopy);
- MoveTo (10, fieldHeight - 14);
- DrawString ("\pRound: ");
- MoveTo (roundH, fieldHeight - 5);
- TextSize (24);
- DrawANumber (roundNumber);
-
- DrawTheScore ();
- MoveTo (eDesH, fieldHeight - 5);
- DrawString ("\pHigh Score: ");
- DrawANumber (highScore);
- }
-
- //• ------------------------------ AllocateFireballs
-
- void AllocateFireballs (Point location)
- {
- short i;
- short idlefb;
-
- idlefb = 0;
-
- for (i = 0; i < maxFB; i++)
- if ((fbs[i].mode == fbIdle) && (idlefb == 0))
- idlefb = i;
-
- if (idlefb != 0)
- {
- SetRect (&fbs[idlefb].bounds, location.h - 30,
- location.v - 30,
- location.h + 30,
- location.v + 30);
- fbs[idlefb].size = 0;
- fbs[idlefb].mode = fbGrow;
- }
- }
-
- //• ------------------------------ AdvanceFireballs
-
- void AdvanceFireballs ()
- {
- short i;
- Rect aRect;
- Rect fbRect; //• Rectangle for drawing fireballs.
-
- PenSize (fbRadRate, fbRadRate);
- PenPat (&qd.black);
- SetRect (&aRect, 0, 0, 60, 60);
-
- for (i = 0; i < maxFB; i++)
- {
- if (fbs[i].mode != fbIdle)
- switch (fbs[i].mode)
- {
- case fbGrow:
- {
- fbs[i].size = fbs[i].size + 1;
- fbBitMap.baseAddr = (Ptr) &fbBits[240 * fbs[i].size - 239]; //• Select a fireball picture.
-
- CopyBits (&fbBitMap, &qd.thePort->portBits, &aRect, &fbs[i].bounds, srcOr, 0L);
-
- if (fbs[i].size >= fbRad)
- fbs[i].mode = fbShrink;
- }
- break;
-
- case fbShrink:
- {
- fbBitMap.baseAddr = (Ptr) &fbBits[240 * fbs[i].size - 239]; //• Select the correct fireball picture.
-
- CopyBits (&fbBitMap, &qd.thePort->portBits, &aRect, &fbs[i].bounds, srcBic, 0L);
-
- fbs[i].size = fbs[i].size - 1;
-
- if (fbs[i].size == 0)
- fbs[i].mode = fbIdle;
- }
- break;
- }
- }
- }
-
- //• ------------------------------ AllocateMissiles
-
- void AllocateMissiles (Point position, short city, short kind)
- {
- short i, idleMS, targetCity, target_H;
-
- for (i = 0, idleMS = 0; i < maxMS; i++)
- if (missiles[i].mode == msIdle && idleMS == 0)
- idleMS = i;
-
- if (idleMS != 0)
- {
- i = idleMS;
-
- //• Set coordinates for beginning of path.
- missiles[i].start.v = position.v;
- missiles[i].start.h = position.h;
-
- //• Initial current position is.
- missiles[i].pos.v = missiles[i].start.v << FP_SHIFT;
-
- //• at start of path.o.
- missiles[i].pos.h = missiles[i].start.h << FP_SHIFT;
-
- //• Speed of Missle
- missiles[i].dv = msSpeed; //• Speed of missile.
-
- //• Now that we know where we're going, calculate the horizontal delta necessary to get there in a vertical
- //• screen-full of iterations.
- missiles[i].city = city + 1;
- target_H = (((missiles[i].city * 2 - 1) * fieldWidth) / (numCities << 1)) << FP_SHIFT;
-
- missiles[i].dh = (target_H - (missiles[i].start.h << FP_SHIFT)) / (((endv - missiles[i].start.v) << FP_SHIFT) / missiles[i].dv);
- missiles[i].kind = kind;
- missiles[i].mode = msActive;
- nMissiles++;
- }
- }
-
-
- //• ------------------------------ BlackPixel
-
- Boolean BlackPixel (Point aPoint)
- {
- aPoint.h = aPoint.h >> FP_SHIFT;
- aPoint.v = aPoint.v >> FP_SHIFT;
- return (GetPixel (aPoint.h, aPoint.v) && GetPixel (aPoint.h + 1, aPoint.v));
- }
-
- //• ------------------------------ AdvanMS
-
- void AdvanMS ()
- {
- short i, j;
- Point newpos, newpixel;
- Boolean detonate;
- short points;
-
- PenMode (patCopy);
-
- for (i = 0; i < maxMS; i++)
- {
- if (missiles[i].mode != msIdle)
- {
- newpos.v = missiles[i].pos.v + missiles[i].dv;
- newpos.h = missiles[i].pos.h + missiles[i].dh;
- newpixel.v = newpos.v >> FP_SHIFT;
- newpixel.h = newpos.h >> FP_SHIFT;
-
- detonate = false;
- if (BlackPixel (newpos) || BlackPixel (missiles[i].pos))
- detonate = true;
-
- PenSize (mWidth, mWidth);
- PenPat (&qd.gray);
- MoveTo (missiles[i].pos.h >> FP_SHIFT, missiles[i].pos.v >> FP_SHIFT);
- LineTo (newpixel.h, newpixel.v);
- missiles[i].pos = newpos;
-
- //• If it's a MIRV, and it's reached the right altitude,
- if ((missiles[i].kind == msMIRV) && (newpixel.v > MIRV_Height))
- {
- //• then make lots of little missiles...
- for (j = 1; j < numCities; j++)
- if ((j != missiles[i].city) && (MunafoRandom (100) < MIRV_Nasty))
- AllocateMissiles (newpixel, j, msNormal);
-
- missiles[i].kind = msNormal;
- }
-
- //• If the missile has reached its target or hit a fireball...
- if ((newpos.v >> FP_SHIFT >= endv) || detonate)
- {
- PenSize (mWidth + 2, mWidth + 2);
- PenPat (&qd.white);
- MoveTo (missiles[i].start.h-1, missiles[i].start.v-1); //• Erase the line.
- LineTo (newpixel.h - 1, newpixel.v - 1);
-
- //•...turn off the missile.
- missiles[i].mode = msIdle;
- nMissiles--;
-
- if (detonate)
- {
- if ((mFlag2 == 2) || ((mFlag2 == 1) && (MunafoRandom (25) > roundNumber)))
- AllocateFireballs (newpixel); //• Make a new fireball.
-
- eDestroyed++;
- Score = Score + MPoints[missiles[i].kind];
- UpdateScore ();
- }
- else
- if (cities[missiles[i].city])
- {
- AllocateFireballs (newpixel);
- cities[missiles[i].city] = false;
- citiesLeft--;
-
- if (citiesLeft + bonusCities == 0)
- gameOver = true;
- }
- }
- }
- }
- }
-
- //• ------------------------------ CenterSomeText
-
- void CenterSomeText (Str255 TheText, short posV)
- {
- MoveTo ((fieldWidth - StringWidth (TheText)) >> 1, posV);
- DrawString (TheText);
- }
-
- //• ------------------------------ ClearTheScreen
-
- void ClearTheScreen ()
- {
- Rect aRect;
-
- aRect.top = 0;
- aRect.left = 0;
- aRect.bottom = fieldHeight;
- aRect.right = fieldWidth;
- FillRect (&aRect, &qd.white);
- }
-
- //• ------------------------------ DrawACity
-
- void DrawACity (short city)
- {
- Point cityLocale;
- short bOffset;
- Rect aRect;
-
- qd.randSeed = 2; //• Make each city look the same.
- cityLocale.v = fieldHeight - cityHeight;
- cityLocale.h = (((city << 1) + 1) * fieldWidth) / (numCities << 1);
- bOffset = - (cityWidth >> 1);
-
- while (bOffset< (cityWidth >> 1))
- {
- aRect.left = cityLocale.h + bOffset;
- aRect.top = cityLocale.v - MunafoRandom (buildHeight);
- aRect.bottom = cityLocale.v + 2;
- aRect.right = aRect.left + buildWidth;
- FillRect (&aRect, &(**cityPattern));
- bOffset = bOffset + buildWidth;
- }
- }
-
- //• ------------------------------ DrawOurStuff
-
- void DrawOurStuff ()
- {
- short i;
- Rect aRect;
-
- ClearTheScreen ();
-
- for (i = 0; i < numCities; i++)
- if (cities[i])
- DrawACity (i);
-
- PenPat (&qd.black);
- qd.randSeed = TickCount (); //• Randomize.
-
- DrawBottomLine ();
- }
-
- //• ------------------------------ NumStrMinMax
-
- short
- NumStrMinMax (Str255 theString, short minimum, short MAXIMUM)
- {
- long theNumber;
-
- StringToNum (theString, &theNumber);
-
- if (theNumber < minimum)
- theNumber = minimum;
-
- if (theNumber > MAXIMUM)
- theNumber = MAXIMUM;
-
- return (theNumber);
- }
-
- //• ------------------------------ DoGameOptions
-
- void DoGameOptions ()
- {
- //• Here are all the magic constants that go with that monster dialog box:
- #define OK 1 //• OK button.
- #define GSpeed 5 //• Game Speed text box.
- #define sRound 7 //• Start Round text box.
- #define MPB 18 //• mpBase text boxes.
- #define MPE 24 //• mpExtra text boxes.
- #define MF1 8 //• mFlag1 check box.
- #define MF2 10 //• mFlag2 radio buttons.
- #define MEX 15 //• mExists check boxes.
-
- GrafPtr savePort; //• For saving the GrafPort and restoring later.
- DialogPtr dPtr; //• Pointer to my dialog box.
- short itemHit; //• Item that was just hit by the user.
- short theType; //• not used.
- Handle theHandle; //• Temp. handle.
- Rect theRect; //• not used.
- Str255 theString; //• Temp. string.
- short theValue; //• Temp. integer value.
- short i; //• Loop Variable.
- short station; //• Current setting of radio buttons.
-
- dPtr = GetNewDialog (optionsDialog, nil, (WindowPtr) -1L);
-
- GetDItem (dPtr, GSpeed, &theType, &theHandle, &theRect); //• Set up all the EditText boxes.
- NumToString (gameSpeed, theString);
- SetIText (theHandle, theString);
-
- GetDItem (dPtr, sRound, &theType, &theHandle, &theRect);
- NumToString (startRound, theString);
- SetIText (theHandle, theString);
-
- for (i = 0; i < 2; i++)
- {
- GetDItem (dPtr, MPB + i, &theType, &theHandle, &theRect); //• Text for points each missile is worth.
- NumToString (mpBase[i + 1], theString);
- SetIText (theHandle, theString);
-
- GetDItem (dPtr, MPB + 3 + i, &theType, &theHandle, &theRect); //• Text for plus sign.
- SetPString (theString, "+");
- SetIText (theHandle, theString);
-
- GetDItem (dPtr, MPE + i, &theType, &theHandle, &theRect); //• Text for additional points each round.
- NumToString (mpExtra[i + 1], theString);
- SetIText (theHandle, theString);
-
- GetDItem (dPtr, MPE + 3 + i, &theType, &theHandle, &theRect); //• text : '* round.
- SetPString (theString, "* round");
- SetIText (theHandle, theString);
-
- GetDItem (dPtr, MEX + i, &theType, &theHandle, &theRect); //• Check boxes for types of missiles.
- theValue = 0;
-
- if (mExists[i + 1])
- theValue = 1;
-
- SetCtlValue ((ControlHandle) theHandle, theValue);
- }
-
- for (i = 0; i < 2; i++)
- { //• Program the radio buttons.
- GetDItem (dPtr, MF2 + i, &theType, &theHandle, &theRect);
- theValue = 0;
- if (mFlag2 == i) theValue = 1;
- SetCtlValue ((ControlHandle) theHandle, theValue);
- }
- station = MF2 + mFlag2;
-
- GetDItem (dPtr, MF1, &theType, &theHandle, &theRect); //• Set check box for mFlag1.
- theValue = 0;
- if (mFlag1) theValue = 1;
- SetCtlValue ((ControlHandle) theHandle, theValue);
-
- SelIText (dPtr, sRound, 0, 1000); //• Initial selection is startRound.
-
- do
- {
- ModalDialog (0L, &itemHit); //• Let them hit an item...
-
- switch (itemHit)
- {
- //• Was it one of our radio buttons?
- case 10:
- case 11:
- case 12:
- GetDItem (dPtr, station, &theType, &theHandle, &theRect); //• Get the old one, and turn it off.
- SetCtlValue ((ControlHandle) theHandle, 0);
- station = itemHit;
-
- GetDItem (dPtr, station, &theType, &theHandle, &theRect); //• Turn this one on.
- SetCtlValue ((ControlHandle) theHandle, 1);
-
- break;
-
- case 18:
- case 15:
- case 16:
- case 17:
- GetDItem (dPtr, itemHit, &theType, &theHandle, &theRect);
- theValue = ! GetCtlValue ((ControlHandle) theHandle); //• Find the value and invert it.
- SetCtlValue ((ControlHandle) theHandle, theValue);
-
- break;
- }
- } while ((itemHit != 1) && (itemHit != 2));
-
- if (itemHit == OK) //• Have to get all the new values now!
- {
- GetDItem (dPtr, GSpeed, &theType, &theHandle, &theRect); //• Set up all the EditText boxes.
- GetIText (theHandle, theString);
- gameSpeed = NumStrMinMax (theString, 1, 99);
-
- GetDItem (dPtr, sRound, &theType, &theHandle, &theRect);
- GetIText (theHandle, theString);
- startRound = NumStrMinMax (theString, 1, 99);
-
- for (i = 0; i < 2; i++)
- {
- //• Text for points each missile is worth.
- GetDItem (dPtr, MPB + i, &theType, &theHandle, &theRect);
- GetIText (theHandle, theString);
- mpBase[i + 1] = NumStrMinMax (theString, -1000, 1000);
-
- //• Text for additional points each round.
- GetDItem (dPtr, MPE + i, &theType, &theHandle, &theRect);
- GetIText (theHandle, theString);
- mpExtra[i + 1] = NumStrMinMax (theString, -1000, 1000);
-
- //• Check boxes for types of missiles.
- GetDItem (dPtr, MEX + i, &theType, &theHandle, &theRect);
- if (GetCtlValue ((ControlHandle) theHandle) == 0)
- mExists[i + 1] = false;
- else
- mExists[i + 1] = true;
- }
-
- for (i = 0; i < 2; i++)
- { //• radio buttons.
- GetDItem (dPtr, MF2 + i, &theType, &theHandle, &theRect);
- if (GetCtlValue ((ControlHandle) theHandle) == 1)
- mFlag2 = i;
- }
-
- GetDItem (dPtr, MF1, &theType, &theHandle, &theRect); //• mFlag1.
- if (GetCtlValue ((ControlHandle) theHandle) == 0)
- mFlag1 = false;
- else
- mFlag1 = true;
- }
-
- DisposDialog (dPtr);
- GetPort (&savePort); //• save whatever port was current.
- SetPort (myWindow);
- InvalRect (&screenRect); //• force the entire screen, including frame, to be redrawn.
- SetPort (savePort);
- }
-
- //• ------------------------------ DoCommand
-
- void DoCommand (long whichMenu)
- {
- short theMenu;
- short theItem;
- Str255 daName;
-
- MenuHandle tempMenu;
-
- theMenu = HiWord (whichMenu);
- theItem = LoWord (whichMenu);
- tempMenu = GetMenu (theMenu);
-
- switch (theMenu)
- {
- case appleMenu:
- switch (theItem)
- {
- case iAbout:
- Alert (aboutAlert, nil);
- break;
-
- default:
- GetItem (GetMHandle (appleMenu), theItem, daName);
- OpenDeskAcc (daName);
- break;
- }
- break;
-
- case fileMenu:
- switch (theItem)
- {
- case iQuit:
- {
- HUnlock ((Handle) crosshair);
- SetCursor (&qd.arrow);
- ExitToShell ();
- }
- }
- break;
-
- case gameMenu:
- switch (theItem)
- {
- case iPause:
- pauseFlag = true; //• pause game.
- break;
-
- case iResume:
- pauseFlag = false; //• resume game.
- break;
-
- case iOptions:
- DoGameOptions ();
- break;
-
- case iNewGame:
- { //• New Game.
- gameOver = true;
- endDelay = 100;
- esFlag = false;
- pauseFlag = false;
- }
- break;
-
- }
- break;
- }
-
- HiliteMenu (0);
- }
-
- //• ------------------------------ CheckEvents
-
- void CheckEvents ()
- {
- Point mousePoint;
- short mouseCode;
- char theChar;
- short i;
- Rect fbRect; //• Rectangle for drawing fireballs.
-
- crosshair2 = GetCursor (257); //• Load the Crosshairs cursor that I use in the game.
- HLockHi ((Handle) crosshair2);
-
- do
- {
- SystemTask ();
-
- GetMouse (&mousePoint);
- LocalToGlobal (&mousePoint);
- mouseCode = FindWindow (mousePoint, &whichWindow);
-
- //• If my window is activated, set cursor:
- if (FrontWindow () == myWindow)
- if ((whichWindow == myWindow) //• If it's above my window,
- && (mouseCode != inMenuBar) //• but not the scroll bar,
- && (! pauseFlag) //• the game is 'active',
- && (FrontWindow () == myWindow) //• my window is in front, .
- && (yLeft > 0)) //• and the user has missiles left, then:.
- SetCursor (*crosshair); //• Set the Missile Command cursor.
- else
- SetCursor (*crosshair2); //• Otherwise, use an arrow.
-
- while (GetNextEvent (everyEvent, &myEvent))
- switch (myEvent.what)
- {
- case mouseDown:
- {
- code = FindWindow (myEvent.where, &whichWindow);
- switch (code)
- {
-
- case inMenuBar:
- DoCommand (MenuSelect (myEvent.where));
- break;
-
- case inSysWindow:
- SystemClick (&myEvent, whichWindow);
- break;
-
- case inDrag:
- DragWindow (whichWindow, myEvent.where, &qd.thePort->portRect);
- break;
-
- case inContent:
- {
- //• Can't select myWindow - must close
- //• other windows.
- if ((whichWindow != FrontWindow ())
- && (whichWindow != myWindow))
- SelectWindow (whichWindow);
- else
- //• Can't make fireballs while paused.
- //• Make sure they have some missiles left.
- //• Game must be running.
- if ((! pauseFlag) && (FrontWindow () == myWindow) && (yLeft > 0))
- {
- GlobalToLocal (&myEvent.where);
-
- //• If it's too low...
- if (myEvent.where.v > nukeHeight)
- myEvent.where.v = nukeHeight; //• ...make it legal.
-
- //• Put a fireball in the list.
- AllocateFireballs (myEvent.where);
-
- //• They have less missiles now...
- yLeft = yLeft - 1;
-
- //• ...let them know.
- UpdateScore ();
- }
- }
- break;
- }
- }
- break;
-
- //• No Autokey - don't want to repeat Option-N.
- case keyDown:
- //• If command key was held down.
- if (myEvent.modifiers & cmdKey)
- {
- theChar = myEvent.message & charCodeMask;
- DoCommand (MenuKey (theChar));
- }
- break;
-
- case updateEvt:
- {
- SetPort (myWindow);
- BeginUpdate (myWindow);
- if (playing)
- {
- for (i = 0; i < numCities; i++)
- if (cities[i])
- {
- DrawACity (i);
- }
-
- //• Randomize after drawing cities.
- qd.randSeed = TickCount ();
-
- for (i = 0; i < maxMS; i++)
- if (missiles[i].mode == msActive)
- {
- PenSize (mWidth, mWidth);
- PenPat (&qd.gray);
- MoveTo (missiles[i].start.h, missiles[i].start.v);
- LineTo (missiles[i].pos.h >> FP_SHIFT, missiles[i].pos.v >> FP_SHIFT);
- }
-
- for (i = 0; i < maxFB; i++)
- if (fbs[i].mode != fbIdle)
- {
- fbRect = fbs[i].bounds;
- InsetRect (&fbRect, 30 - 2 * fbs[i].size, 30 - 2 * fbs[i].size);
- PenMode (patCopy);
- FillOval (&fbRect, &qd.black);
- }
- }
-
- DrawBottomLine ();
-
- EndUpdate (myWindow);
- }
- break;
- }
-
- //• If another window has been selected don't do anything except
- //• process events until game window is re-selected.
- } while (! (FrontWindow () == myWindow) && ! pauseFlag);
- } //• CheckEvents.
-
- //• ------------------------------ GameOverScreen
-
- void GameOverScreen ()
- {
- Rect aRect;
- short i;
- short GameOffset, OverOffset;
- Point Center;
-
- TextSize (72);
- TextMode (srcBic);
- PenMode (patOr);
- PenPat (&qd.black);
- PenSize (5, 5);
-
- GameOffset = StringWidth ("\pGAME") >> 1;
- OverOffset = StringWidth ("\pOVER") >> 1;
- Center.v = fieldHeight >> 1;
- Center.h = fieldWidth >> 1;
-
- SetRect (&aRect, Center.h, Center.v, Center.h, Center.v);
-
- for (i = 0; i < 30; i++)
- {
- CheckEvents ();
-
- InsetRect (&aRect, -5, -5);
- FrameOval (&aRect);
- TextSize (72);
- TextMode (srcBic);
- CenterSomeText ("\pGAME", Center.v - 12);
- CenterSomeText ("\pOVER", Center.v + 60);
- }
-
- PenMode (patBic);
- for (i = 0; i < 30; i++)
- {
- CheckEvents ();
-
- FrameOval (&aRect);
- InsetRect (&aRect, 5, 5);
- }
-
- }
-
- //• ------------------------------ InitializeRound
-
- void InitializeRound ()
- {
- short i, rMissiles, yMissiles;
-
- endDelay = 0;
- playing = true;
- roundOver = FALSE;
-
- DrawOurStuff (); //• Redraw screen.
-
- for (i = 0; i < maxFB; i++)
- fbs[i].mode = fbIdle;
-
- for (i = 0; i < maxMS; i++)
- missiles[i].mode = msIdle;
-
- for (i = 0; i < 3; i++)
- MPoints[i] = mpBase[i] + mpExtra[i] * roundNumber;
-
- for (i = 0; i < numCities; i++)
- cities2[i] = cities[i];
-
- nMissiles = 0;
- MIRV_Rate = 0;
- MIRV_Height = fieldHeight >> 2;
- MIRV_Nasty = 30;
- msSpeed = 60;
-
- if (roundNumber > 2)
- MIRV_Rate = 10;
-
- if (roundNumber > 4)
- msSpeed = 80;
-
- if (roundNumber > 6)
- MIRV_Rate = 20;
-
- if (roundNumber > 8)
- MIRV_Nasty = 50;
-
- if (roundNumber > 10)
- MIRV_Height = fieldHeight / 3;
-
- if (roundNumber > 12)
- msSpeed = 90;
-
- if (roundNumber > 14)
- MIRV_Rate = 30;
-
- if (roundNumber > 19)
- msSpeed = 100;
-
- msRate = 5 + roundNumber;
- rMissiles = (roundNumber * roundNumber) / 6 + roundNumber + 6; //• Compute # of enemy missiles.
- yMissiles = rMissiles + roundNumber; //• Adjust yMissiles accordingly.
- eLeft = rMissiles;
- yLeft = yMissiles;
- roundNumber = roundNumber + 1;
-
- if ((roundNumber % 5) == 0)
- bonusCities = bonusCities + 1;
-
- DrawBottomLine ();
- FlushEvents (everyEvent, 0); //• Ignore unprocessed events from previous round.
- }
-
- //• ------------------------------ EndRoundBonus
-
- void EndRoundBonus ()
- {
- short i, points;
- Str255 aString, s;
- char tempString[256];
-
- ClearTheScreen ();
- DrawBottomLine ();
-
- TextSize (24);
- TextMode (srcCopy);
-
- sprintf (tempString, "End of round %d", roundNumber);
- SetPString (aString, tempString);
-
- if (citiesLeft > 0) //• give bonus points for cities.
- {
- CenterSomeText (aString, 100);
- CenterSomeText ("\pBonus:", 130);
- points = 0;
-
- for (i = 0; i < numCities; i++)
- if ((cities[i] && !doneFlag))
- {
- lastTick = TickCount ();
- DrawACity (i);
- points = points + roundNumber * 20;
- Score = Score + roundNumber * 20;
- TextSize (24);
- NumToString (points, s);
- CenterSomeText (s, 160);
- UpdateScore ();
-
- do
- {
- CheckEvents ();
- } while (! (TickCount () >= lastTick + 30) || doneFlag);
- }
- }
-
- if ((bonusCities > 0) && (citiesLeft < 6)) //• Give a bonus city.
- {
- lastTick = TickCount ();
- TextSize (24);
- CenterSomeText ("\p* Bonus City *", 190);
- citiesLeft = citiesLeft + 1;
- bonusCities = bonusCities - 1;
-
- do
- {
- i = MunafoRandom (6);
- } while (! (! cities[i]));
-
- cities[i] = true;
-
- do
- {
- CheckEvents ();
- } while (! (TickCount () >= lastTick + 60) || doneFlag);
- }
- }
-
-
- //• ------------------------------ PlayMacMissile
-
- void PlayMacMissile ()
- {
- short i;
- Str255 s;
- Point msPoint;
- short msCity, msKind;
- short rMissiles; //• "round missiles" - number to set eLeft to each round.
- short yMissiles; //• "your Missiles" - similar to rMissiles.
- Str255 aString;
- short points;
-
- roundNumber = startRound; //• Start out at this round.
- Score = 0;
- eDestroyed = 0;
-
- for (i = 0; i < numCities; i++)
- cities[i] = true;
-
- citiesLeft = numCities;
- bonusCities = 0;
-
- nukeHeight = fieldHeight - cityHeight - (buildHeight >> 1) - (fbRad * fbRadRate);
- endv = fieldHeight - cityHeight - (buildHeight >> 1);
-
- gameOver = false;
- esFlag = true;
- lastTick = TickCount ();
-
- do //• Repeat loop for playing rounds.
- {
- InitializeRound ();
-
- do //• Repeat loop for animating objects in game.
- {
- CheckEvents ();
-
- if (TickCount () >= lastTick + gameSpeed) //• If enough time has elapsed since the last update, update objects on screen.
- {
- lastTick = TickCount ();
-
- if ((eLeft < 1) && (nMissiles < 1))
- roundOver = true;
-
- if (roundOver || gameOver)
- endDelay = endDelay + 1;
- else
- if ((MunafoRandom (100) < msRate) && (eLeft > 0))
- { //• Launch an enemy missile every now and then.
- eLeft = eLeft - 1;
- msPoint.v = 0;
- msPoint.h = MunafoRandom (fieldWidth - 4);
-
- do
- {
- msCity = MunafoRandom (numCities); //• Pick a city.
- } while (! (((MunafoRandom (3) == 1) && mFlag1) || cities2[msCity])); //• Try again for most missiles if city was destroyed.
-
- msKind = 0;
- if (mExists[msNormal])
- msKind = msNormal;
-
- if ((MunafoRandom (100) <= MIRV_Rate) && mExists[msMIRV])
- msKind = msMIRV;
-
- if (msKind == 0)
- msKind = msNormal;
-
- AllocateMissiles (msPoint, msCity, msKind);
- }
-
- AdvanceFireballs (); //• Advance state of fireballs.
- AdvanMS (); //• Advance position of missiles.
- }
- } while (! (((gameOver || roundOver) && (endDelay > 30)) || doneFlag));
-
- playing = false;
-
- if (esFlag && (citiesLeft + bonusCities > 0) && !doneFlag)
- EndRoundBonus ();
-
- } while (! (gameOver || doneFlag));
-
- if (Score > highScore)
- highScore = Score;
-
- if (esFlag)
- GameOverScreen ();
- }
-
- //• ------------------------------ main
-
- void main ()
- {
- SetupEverything ();
-
- do
- {
- PlayMacMissile ();
- } while (!doneFlag);
- }
-
- //• ------------------------------ SetPString
-
- void SetPString (Str255 thePString, char *theCString)
- {
- CtoPstr (theCString);
- BlockMove (theCString, thePString, theCString[0] + 1);
- }